package com.smartian.dnshosts;

/**
 * smartian - 2021-06-26
 */
public class InetAddressUtils {
    private static final int INADDR4SZ = 4;
    private static final int INADDR16SZ = 16;
    private static final int INT16SZ = 2;

    public static byte[] textToNumericFormatV4(String host) {
        byte[] address = new byte[INADDR4SZ];
        long segmentSum = 0L;
        int index = 0;
        boolean readNextSegment = true;
        int hostLength = host.length();
        if (hostLength != 0 && hostLength <= 15) {
            for(int i = 0; i < hostLength; ++i) {
                char ch = host.charAt(i);
                if (ch == '.') {
                    if (readNextSegment || segmentSum < 0L || segmentSum > 255L || index == 3) {
                        return null;
                    }
                    address[index++] = (byte)((int)(segmentSum & 255L));
                    segmentSum = 0L;
                    readNextSegment = true;
                } else {
                    int digit = Character.digit(ch, 10);
                    if (digit < 0) {
                        return null;
                    }

                    segmentSum *= 10L;
                    segmentSum += (long)digit;
                    readNextSegment = false;
                }
            }
            if (!readNextSegment && segmentSum >= 0L && segmentSum < 1L << (4 - index) * 8) {
                switch(index) {
                    case 0:
                        address[0] = (byte)((int)(segmentSum >> 24 & 255L));
                    case 1:
                        address[1] = (byte)((int)(segmentSum >> 16 & 255L));
                    case 2:
                        address[2] = (byte)((int)(segmentSum >> 8 & 255L));
                    case 3:
                        address[3] = (byte)((int)(segmentSum >> 0 & 255L));
                    default:
                        return address;
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    public static byte[] textToNumericFormatV6(String host) {
        if (host.length() < 2) {
            return null;
        } else {
            char[] hostCharArray = host.toCharArray();
            byte[] address = new byte[INADDR16SZ];
            int hostLength = hostCharArray.length;
            int index = host.indexOf("%");
            if (index == hostLength - 1) {
                return null;
            } else {
                if (index != -1) {
                    hostLength = index;
                }

                int var1 = -1;
                int pos = 0;
                int position = 0;
                if (hostCharArray[pos] == ':') {
                    ++pos;
                    if (hostCharArray[pos] != ':') {
                        return null;
                    }
                }
                int startIndex = pos;
                boolean var3 = false;
                int var4 = 0;
                while(true) {
                    int digit;
                    while(pos < hostLength) {
                        char ch = hostCharArray[pos++];
                        digit = Character.digit(ch, 16);
                        if (digit != -1) {
                            var4 <<= 4;
                            var4 |= digit;
                            if (var4 > 65535) {
                                return null;
                            }

                            var3 = true;
                        } else {
                            if (ch != ':') {
                                if (ch == '.' && position + 4 <= 16) {
                                    String segment = host.substring(startIndex, hostLength);
                                    int var14 = 0;

                                    for(int k = 0; (k = segment.indexOf(46, k)) != -1; ++k) {
                                        ++var14;
                                    }

                                    if (var14 != 3) {
                                        return null;
                                    }

                                    byte[] numericFormatV4 = textToNumericFormatV4(segment);
                                    if (numericFormatV4 == null) {
                                        return null;
                                    }

                                    for(int h = 0; h < 4; ++h) {
                                        address[position++] = numericFormatV4[h];
                                    }

                                    var3 = false;
                                    break;
                                }
                                return null;
                            }
                            startIndex = pos;
                            if (!var3) {
                                if (var1 != -1) {
                                    return null;
                                }
                                var1 = position;
                            } else {
                                if (pos == hostLength) {
                                    return null;
                                }
                                if (position + 2 > 16) {
                                    return null;
                                }
                                address[position++] = (byte)(var4 >> 8 & 255);
                                address[position++] = (byte)(var4 & 255);
                                var3 = false;
                                var4 = 0;
                            }
                        }
                    }

                    if (var3) {
                        if (position + 2 > 16) {
                            return null;
                        }

                        address[position++] = (byte)(var4 >> 8 & 255);
                        address[position++] = (byte)(var4 & 255);
                    }

                    if (var1 != -1) {
                        digit = position - var1;
                        if (position == 16) {
                            return null;
                        }

                        for(pos = 1; pos <= digit; ++pos) {
                            address[16 - pos] = address[var1 + digit - pos];
                            address[var1 + digit - pos] = 0;
                        }

                        position = 16;
                    }

                    if (position != 16) {
                        return null;
                    }

                    byte[] result = convertFromIPv4MappedAddress(address);
                    if (result != null) {
                        return result;
                    }
                    return address;
                }
            }
        }
    }
    public static boolean isIPv4LiteralAddress(String host) {
        return textToNumericFormatV4(host) != null;
    }
    public static boolean isIPv6LiteralAddress(String host) {
        return textToNumericFormatV6(host) != null;
    }
    public static byte[] convertFromIPv4MappedAddress(byte[] address) {
        if (isIPv4MappedAddress(address)) {
            byte[] result = new byte[4];
            System.arraycopy(address, 12, result, 0, 4);
            return result;
        } else {
            return null;
        }
    }
    private static boolean isIPv4MappedAddress(byte[] address) {
        if (address.length < 16) {
            return false;
        } else {
            return address[0] == 0 && address[1] == 0 && address[2] == 0 && address[3] == 0 && address[4] == 0 && address[5] == 0 && address[6] == 0 && address[7] == 0 && address[8] == 0 && address[9] == 0 && address[10] == -1 && address[11] == -1;
        }
    }
    public static boolean isMatcherIpV4OrIpV6(String hostname) {
        return InetAddressUtils.isIPv4LiteralAddress(hostname) || InetAddressUtils.isIPv6LiteralAddress(hostname);
    }
}
